/*
FuStA: FuDePAN's Statistical Analysis package.
    Copyright (C) 2011  Daniel Gutson, FuDePAN

    This file is part of FuStA Minimalistic Library.

    FuStA is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    FuStA is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with FuStA.  If not, see <http://www.gnu.org/licenses/>.

    This is the inline implementation file.
*/

#ifndef FUSTA_H
#error Do not include this file. Include fusta.h instead.
#else

#include <iostream>
#include <fstream>

namespace fusta {

template <class Number>
struct StatSerieInterface
{
    virtual void addNumber(Number number) = 0;
    virtual void addImplementation(StatSerieInterface* impl) = 0;
    virtual ~StatSerieInterface(){}
};

// ------------------ StatSerie implementation --------------

template <class Number>
StatSerie<Number>::StatSerie()
    : first(NULL)
{}

template <class Number>
StatSerie<Number>::~StatSerie()
{
    delete first;
}

template <class Number>
StatSerie<Number>& StatSerie<Number>::addNumber(Number number)
{
    first->addNumber(number);
    return *this;
}

template <class Number>
template <class Implementation>
Implementation& StatSerie<Number>::addImplementation(Implementation* impl)
{
    if (first == NULL)
        first = impl;
    else
        first->addImplementation(impl);

    return *impl;
}

// ----------------- Series Implementations ----------------------

// Base Implementation
template <class Number>
class StatBaseImplementation : public StatSerieInterface<Number>
{
    StatSerieInterface<Number>* next;

    virtual void _addNumber(Number number) = 0; // to be implemented by implementation

    virtual void addNumber(Number number)
    {
        _addNumber(number);
        if (next != NULL)
            next->addNumber(number);
    }

    virtual void addImplementation(StatSerieInterface<Number>* impl)
    {
        if (next == NULL)
            next = impl;
        else
            next->addImplementation(impl);
    }

public:
    StatBaseImplementation() : next(NULL) {}
    ~StatBaseImplementation()
    {
        delete next;
    }
};

// Output (to screen or file) implementation --------------------
template <class Number>
class OutputSerie : public StatBaseImplementation<Number>
{
    virtual void _addNumber(Number number)
    {
        std::cout << number << std::endl;
    }
};

// Statistical Summary implementation --------------------
template <class Number>
class StatSummary : public StatBaseImplementation<Number>
{
    size_t count;
    Number sum;

    virtual void _addNumber(Number number)
    {
        count++;
        sum += number;
    }

public:
    StatSummary()
        : count(0), sum(Number(0))
    {}

    Number average() const
    {
        return sum / count;
    }
};

// Output to R file implementation --------------------
template <class Number>
class StatR : public StatBaseImplementation<Number>
{
    std::ofstream file;

    virtual void _addNumber(Number number)
    {
        file << number << std::endl;
    }

public:
    StatR(const char* filename)
        : file(filename)
    {}
};

}

#endif

